#include "json.h"
#include "parser.h"
#include<sstream>
using namespace std;
Json::Json(): m_type(json_null){

}
Json::Json(bool value):m_type(json_bool){
    m_value.m_bool = value;
}
Json::Json(int value):m_type(json_int){
    m_value.m_int = value;
}
Json::Json(double value): m_type(json_double){
    m_value.m_double = value;
}
Json::Json(const char* value): m_type(json_string){
    m_value.m_string = new string(value);
}
Json::Json(const string & value): m_type(json_string){
    m_value.m_string = new string(value);
}
Json::Json(Type type): m_type(type){
    switch (type)
    {
    case json_null:
        break;
    case json_bool:
        m_value.m_bool = false;
        break;
    case json_int:
        m_value.m_int = 0;
        break;
    case json_double:
        m_value.m_double = 0.0;
        break;
    case json_array:
        m_value.m_array = new vector<Json>();
        break;
    case json_object:
        m_value.m_object = new map<string, Json>();
        break;
    case json_string:
        m_value.m_string = new string("");
        break;
    default:
        break;
    }
}    
Json::Json(const Json & other){
    copy(other);
}
Json::operator bool(){
    if(m_type != json_bool){
        perror("type error, not bool value");
    }
    return m_value.m_bool;
}
Json::operator int(){
    if(m_type != json_int){
        perror("tyoe error, not int value");
    }
    return m_value.m_int;
}
Json::operator double(){
    if(m_type != json_double){
        perror("type error, not double type");
        
    }
    return m_value.m_double;
}
Json::operator string(){
    if(m_type != json_string){
        perror("type error, not string value");
    }
    return *(m_value.m_string);
}
Json & Json::operator [] (int index){
    if(m_type != json_array){
        m_type = json_array;
        m_value.m_array = new vector<Json>();
    }
    if(index < 0){
        perror("array[] index < 0");
    }
    int size = m_value.m_array->size();
    if(index >= size){
        for(int i=index; i < size; i++){
            m_value.m_array->push_back(Json());
        }
    }
    return m_value.m_array->at(index);
}
void Json::append(const Json & other){
    if(m_type != json_array){
        clear();
        m_type = json_array;
        m_value.m_array = new vector<Json>();
    }
    m_value.m_array->push_back(other);
}
string Json::str() const{
    stringstream ss;
    switch (m_type)
    {
    case json_null:
        ss << "null";
        break;
    case json_int:
        ss << m_value.m_int;
        break;
    case json_double:
        ss << m_value.m_double;
        break;
    case json_string:
        ss << '\"' << *(m_value.m_string) << '\"';
        break;
    case json_bool:
        if(m_value.m_bool){
            ss << "true";
        }else{
            ss << "false";
        }
        break;
    case json_array:
        {
            ss << "[";
            for(auto i= m_value.m_array->begin(); i != m_value.m_array->end(); i++){
                if(i != m_value.m_array->begin()){
                    ss << ",";
                }
                ss << i->str();
            }
            ss << "]";
        }
        break;
    case json_object:
        {
            ss << "{";
            for(auto i= m_value.m_object->begin(); i != m_value.m_object->end(); i++){
                if(i != m_value.m_object->begin()){
                    ss << ",";
                }
                ss << '\"' << i->first << '\"' << ':' << i->second.str();
            }
            ss << "}";
        }
        break;
    default:
        break;
    }
    return ss.str();
}
void Json::copy(const Json & other){
    clear();
    m_type = other.m_type;
    switch (m_type)
    {
    case json_null:
        break;
    case json_bool:
        m_value.m_bool = other.m_value.m_bool;
        break;
    case json_int:
        m_value.m_int = other.m_value.m_int;
        break;
    case json_double:
        m_value.m_double = other.m_value.m_double;
        break;
    case json_array:
        m_value.m_array = other.m_value.m_array;
        break;
    case json_object:
        m_value.m_object = other.m_value.m_object;
        break;
    case json_string:
        m_value.m_string = other.m_value.m_string;
        break;
    default:
        break;
    }  
}
void Json::clear(){
    switch (m_type)
    {
    case json_null:
        break;
    case json_bool:
        m_value.m_bool = false;
        break;
    case json_int:
        m_value.m_int = 0;
        break;
    case json_double:
        m_value.m_double = 0.0;
        break;
    case json_array:
        {
            for(auto i=m_value.m_array->begin(); i != m_value.m_array->end(); i++){
                i->clear();
            }
            delete m_value.m_array;
            m_value.m_array = nullptr;
        }
        break;
    case json_object:
        {
            for(auto i=m_value.m_object->begin(); i != m_value.m_object->end(); i++){
                i->second.clear();
            }
            delete m_value.m_object;
            m_value.m_object = nullptr;
        }
        break;
    case json_string:
        {
            delete m_value.m_string;
            m_value.m_string = nullptr;
        }
        break;
    default:
        break;
    }
    m_type = json_null;
}
Json & Json::operator [] (const char* key){
    string name(key);
    return (*(this))[name];
}
Json & Json::operator [] (const string & key){
    if(m_type != json_object){
        clear();
        m_type = json_object;
        m_value.m_object = new map<string, Json>();
    }
    return (*(m_value.m_object))[key];
}
void Json::operator = (const Json & other){
    copy(other);
}
bool Json::operator == (const Json & other){
    if(m_type != other.m_type){
        return false;
    }
    switch (m_type)
    {
    case json_null:
        return true;
        break;
    case json_int:
        return m_value.m_int == other.m_value.m_int;
        break;
    case json_double:
        return m_value.m_double == other.m_value.m_double;
        break;
    case json_bool:
        return m_value.m_bool == other.m_value.m_bool;
        break;
    case json_array:
        return m_value.m_array == other.m_value.m_array;
        break;
    case json_string:
        return *(m_value.m_string) == *(other.m_value.m_string);
        break;
    case json_object:
        return m_value.m_object == other.m_value.m_object;
        break;
    default:
        break;
    }
    return false;
}
bool Json::operator != (const Json & other){
    return !((*this) == other);
}
int Json::asInt() const{
    if(m_type != json_int){
        perror("type error, not int value");
    } 
    return m_value.m_int;
}
double Json::asDouble() const{
    if(m_type != json_int){
        perror("type error, not double value");
    } 
    return m_value.m_double;
}
bool Json::asBool() const{
    if(m_type != json_int){
        perror("type error, not bool value");
    } 
    return m_value.m_bool;
}
string Json::asString() const{
    if(m_type != json_int){
        perror("type error, not string value");
    } 
    return *(m_value.m_string);
}
bool Json::has(const int index){
    if(m_type != json_array){
        return false;
    }
    int size = m_value.m_array->size();
    return (index >=0) && (index < size);
}
bool Json::has(const char* key){
    string name(key);
    has(name);
}
bool Json::has(const string & key){
    if(m_type != json_string){
        return false;
    }
    return m_value.m_object->find(key) != m_value.m_object->end();
}
void Json::remove(const int index){
    if(has(index)){
        m_value.m_array->at(index).clear();
        m_value.m_array->erase(m_value.m_array->begin()+index);
    }
}
void Json::remove(const char* key){
    string name(key);
    remove(key);
}
void Json::remove(const string & key){
    if(has(key)){
        (*m_value.m_object)[key].clear();
        m_value.m_object->erase(key);
    }
}
void Json::parser(const string & str){
    Parser p;
    p.load(str);
    *this = p.parser();
}